<?php

namespace App\HttpController;


use App\Model\Service\LoginService;
use EasySwoole\EasySwoole\ServerManager;
use EasySwoole\Http\AbstractInterface\Controller;
use EasySwoole\Redis\Redis;
use EasySwoole\RedisPool\RedisPool;
use EasySwoole\Utility\Str;
use EasySwoole\Validate\Exception\Runtime;
use EasySwoole\Validate\Validate;
use Trois\Lib\HandleMessage;

abstract class SuperBase extends Controller
{

    use HandleMessage;

    protected array $loginUser = [];

    /**
     * post参数
     * @var array
     */
    protected array $postParams = [];

    protected abstract function getValidate(string $actionName): array;

    protected abstract function initService(array $postParams, array $loginUser): void;

    /**
     * 获取用户的真实IP
     * @param string $headerName 代理服务器传递的标头名称
     * @return string
     */
    protected function clientRealIP(string $headerName = 'x-real-ip'): string
    {
        $server = ServerManager::getInstance()->getSwooleServer();
        $client = $server->getClientInfo($this->request()->getSwooleRequest()->fd);
        $clientAddress = $client['remote_ip'] ?? '127.0.0.1';
        $xri = $this->request()->getHeader($headerName);
        $xff = $this->request()->getHeader('x-forwarded-for');
        if ($clientAddress === '127.0.0.1') {
            if (!empty($xri)) {  // 如果有 xri 则判定为前端有 NGINX 等代理
                $clientAddress = $xri[0];
            } elseif (!empty($xff)) {  // 如果不存在 xri 则继续判断 xff
                $list = explode(',', $xff[0]);
                if (isset($list[0])) $clientAddress = $list[0];
            }
        }
        return $clientAddress ?: '127.0.0.1';
    }

    protected function success($data = '', string $message = 'success', int $code = 1): bool
    {
        return $this->responseJson(200, $message, $data, $code);
    }

    protected function error(string $message = '操作失败', array $data = [], int $code = 0): bool
    {
        return $this->responseJson(400, $message, $data, $code);
    }

    private function responseJson(int $httpCode, string $message, $data = '', int $code = 0): bool
    {
        if (!$this->response()->isEndResponse()) {
            $data = array(
                "code" => $code,
                "data" => $data,
                "msg" => $message,
                "time" => time()
            );
            $this->response()->write(json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
            $this->response()->withHeader('Content-type', 'application/json;charset=utf-8');
            $this->response()->withStatus($httpCode);
            return true;
        } else {
            return false;
        }

    }

    public function responseJsonForUe(int $httpCode, array $data = []): bool
    {
        if (!$this->response()->isEndResponse()) {
            $this->response()->write(json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
            $this->response()->withHeader('Content-type', 'application/json;charset=utf-8');
            $this->response()->withStatus($httpCode);
            return true;
        } else {
            return false;
        }

    }


    public function getPostParams(): array
    {
        $postParams = $this->request()->getParsedBody();  //form-data 方式提交

        if (!$postParams) {
            $content = $this->request()->getBody()->__toString();  //application/json 方式提交
            $postParams = json_decode($content, true);
        }

        $postParams = $postParams ?? [];

        foreach ($postParams as $k => $v) {
            $postParams[$k] = trimAll($v);  //过滤掉字符串类型的空格
        }

        $this->postParams = $postParams;

        return $this->postParams;
    }

    /**
     * 检查控制器是否定义getValidate方法,并自动调用
     */
    public function checkValidate(): array
    {

        $path_info = explode('/', $this->request()->getUri()->getPath());
        $actionName = end($path_info);

        //调用控制中的getValidate方法，获取验证数据
        $vData = call_user_func_array([$this, 'getValidate'], [$actionName]);

//        $vData = [
//            'name' => 'required=name不能为空,notEmpty,allowFile=array-png|jpg',
//        ];

        // 列表时注入分页参数验证
        if ($actionName == 'list'
            && $vData
            && isset($this->postParams['needPage'])
            && $this->postParams['needPage']) {
            $vData = array_merge($vData, [
                'page' => 'required,notEmpty,integer',
                'limit' => 'required,notEmpty,integer,max=200',
            ]);
        }

        $validate = new Validate();

        $validateData = [];

        foreach ($vData as $ruleField => $rules) {

            $column = $validate->addColumn($ruleField);

            foreach (explode(',', $rules) as $rule) {

                $rule = explode('=', $rule);

                if (count($rule) > 1 && Str::startsWith($rule[1], 'array')) {
                    $_r1 = explode('-', $rule[1]);
                    $rule[1] = explode('|', $_r1[1]);
                }

                call_user_func_array([$column, $rule[0]], [$rule[1] ?? null]);
            }

            $validateData[$ruleField] = $this->postParams[$ruleField] ?? '';

        }

        try {

            $bool = $validate->validate($validateData);

            if (!$bool) {
                return [0, $validate->getError()->__toString()];
            }

            return [1, $validateData];

        } catch (Runtime $e) {
            return [0, $e->getMessage()];
        }


    }

    protected function verifyToken(string $token): bool
    {

        $user = RedisPool::invoke(function (Redis $redis) use ($token) {

            $userId = $redis->get(LoginService::$userTokenKeyPre . $token);

            if (!$userId) {
                return [];
            }

            $userInfo = $redis->get(LoginService::$userTokenBuildIdKeyPre . $userId);

            return $userInfo ? json_decode($userInfo, true) : [];

        });

        if (!$user || !isset($user['user_id'])) {
            return false;
        }

        $this->loginUser = $user;

        return true;

    }


}